#include "matrix.h"

Matrix *make_zeros(size_t row, size_t col) {
  Matrix *m = (Matrix *)malloc(sizeof(Matrix));
  double *arr = (double *)calloc(row * col, sizeof(double));

  m->row = row;
  m->col = col;
  m->arr = arr;
  m->type = MATRIX;
  return m;
}

void destroy_matrix(Matrix *m) {
  if (m->type == MATRIX)
    free(m->arr);
  free(m);
}

inline double *get_item(Matrix *m, size_t i, size_t j) {
  return m->arr + (i * m->col + j);
}

void display(FILE *fp, Matrix *m) {
  for (size_t i = 0; i < m->row; ++i) {
    for (size_t j = 0; j < m->col; ++j) {
      fprintf(fp, "%.3lf\t", *get_item(m, i, j));
    }
    fprintf(fp, "\n");
  }
}

void write_matrix(FILE *fp, Matrix *m) {
  fprintf(fp, "%zu %zu\n", m->row, m->col);
  for (size_t i = 0; i < m->row; ++i) {
    fprintf(fp, "# Row %zu\n", i);
    for (size_t j = 0; j < m->col; ++j) {
      fprintf(fp, "%lf\n", *get_item(m, i, j));
    }
  }
}

Matrix *read_matrix(FILE *fp) {
  size_t row, col;
  fscanf(fp, "%zu %zu\n", &row, &col);

  Matrix *m = make_zeros(row, col);

  char buff[100];
  size_t i = 0;
  while (fgets(buff, 100, fp)) {
    if (buff[0] == '#') {
      continue;
    }
    double item = atof(buff);
    *get_item(m, 0, i++) = item;
  }

  return m;
}

Matrix *open_read_matrix(const char *file_name) {
  FILE *fp = fopen(file_name, "r");
  if (fp == NULL) {
    fprintf(stderr, "%s", "Can't open the file");
    return NULL;
  }

  Matrix *m = read_matrix(fp);

  fclose(fp);
  return m;
}

Matrix *get_sub(Matrix *src, size_t *lt, size_t *rb) {
  size_t row = rb[0] - lt[0] + 1;
  size_t col = rb[1] - lt[1] + 1;

  Matrix *sub = malloc(sizeof(Matrix));
  sub->col = col;
  sub->row = row;
  sub->arr = src->arr + (col * lt[0] + lt[1]);
  sub->type = SUB_MATRIX;

  return sub;
}

void dot(Matrix *src1, Matrix *src2, Matrix *tar) {
  for (size_t i = 0; i < src1->row; ++i) {
    for (size_t j = 0; j < src2->col; ++j) {
      double sum = 0;
      for (size_t k = 0; k < src1->col; ++k) {
        sum += *(get_item(src1, i, k)) * *(get_item(src2, k, j));
      }
      *(get_item(tar, i, j)) = sum;
    }
  }
}